<!DOCTYPE html>
<html lang="zh-Hans">
<meta name="theme-color" content="#FFFFFF">


<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
  <meta name="theme-color" content="#202020"/>
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <link rel="shortcut icon" href="/images/favicon.ico" type="image/x-icon" />
  <link rel="icon" sizes="any" mask href="/images/favicon.ico" /> 
  
  

  <!-- viewjs support -->
  
    <!-- for theme: default is false -->
    <!-- for page: default is true -->
    <link  href="./css/viewer.min.css" rel="stylesheet" >
    <script src="./js/viewer.min.js" type="text/javascript" charset="utf-8"></script>
  
  
  
    <meta name="keywords" content="" />
  

  
    <meta name="description" content="分享 Java 技术，做有趣的程序员" />
  
  
  <link rel="icon" type="image/x-icon" href="/logo.png">
  <title> [ H E R O ]❖ZhangBo&#39;s Tech Blog</title>
  
    <!-- stylesheets list from config.yml -->
    
      <link rel="stylesheet" href="//cdn.bootcss.com/pure/1.0.0/pure-min.css">
    
      <link rel="stylesheet" href="/css/xoxo.css">
    
  
<meta name="generator" content="Hexo 5.4.0"></head>


<body>
  <div class="nav-container">
    <nav id="menu" class="home-menu pure-menu pure-menu-horizontal">
  <a class="pure-menu-heading" href="/">
    <!-- <img class="avatar" src="/images/logo.png"> -->
    <span class="title">H E R O</span>
  </a>

  <ul class="pure-menu-list clearfix">
      
          
            <li class="pure-menu-item actived"><a href="/" class="pure-menu-link">首页</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/archives/" class="pure-menu-link">归档</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/tags/" class="pure-menu-link">标签</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/about/" class="pure-menu-link">关于</a></li>
          
      
          
            <li class="pure-menu-item"><a href="/atom.xml" class="pure-menu-link">订阅</a></li>
          
      
  </ul>
   
</nav>
  </div>

  <div class="container" id="content-outer">
    <div class="inner" id="content-inner">
      

  <div class="recent-posts">
    

      <article class="recent-post-item">
        <a class="title" href="/about-git-dff.html"><h2>到底什么是 Git 三方对比</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2021-11-04T12:44:39.000Z">
            2021-11-04
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/Git/" rel="tag">Git</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>问题： 为什么我在 gitlab 上提交的MR，代码diff不是两个分支的区别？</p>
<p>带有场景的举例子：</p>
<p>小A 在linke上建立的新的迭代，同时生成了代码分支 <code>dev</code>，然后 A、B两个同学都在这个迭代进行开发。小 A 基于 <code>dev</code> 分支创建了 <code>dev_A</code> 分支，小B基于dev分支创建了<code>dev_B</code> 分支。后来小A将他的变更合并到了 dev 分支，小B在开发过程中由于和master分支有冲突，所以他在本地解决冲突合并了一下 master 分支，然后又合并了一下 dev 分支，然后推送到 antcode 进行 MR，发现MR中代入了 master 的代码，和小A已经提交的代码？why？<br>
          </div>
        
        <a class="more" href="/about-git-dff.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/OpenClash-AdguardHome-work-toghter.html"><h2>OpenClash 搭配 Adguard Home 使用</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2021-07-25T16:25:33.000Z">
            2021-07-26
          </time>
          
          <span class="slash">/</span>
          
          
          

        </div>

        
          <div class="post-excerpt">
            <p>openwrt 中 openclash 和 adguard home 搭配使用的配置教程。</p>
          </div>
        
        <a class="more" href="/OpenClash-AdguardHome-work-toghter.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/how-get-antfin-offer.html"><h2>[面经] 如何拿下阿里/蚂蚁 offer</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2019-08-24T05:13:56.000Z">
            2019-08-24
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E8%9A%82%E8%9A%81%E9%87%91%E6%9C%8D/" rel="tag">蚂蚁金服</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E9%98%BF%E9%87%8C/" rel="tag">阿里</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E9%9D%A2%E7%BB%8F/" rel="tag">面经</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>总结一下我的阿里面试，做一个记录吧。分享给需要的人。</p>
          </div>
        
        <a class="more" href="/how-get-antfin-offer.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/solve-dp-problems.html"><h2>如何解决动态规划问题</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2019-07-29T15:46:19.000Z">
            2019-07-29
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E7%AE%97%E6%B3%95/" rel="tag">算法</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>曾经的我以为动态规划很神秘，很难理解。后来随着刷的动态规划相关的题越来越多，对于动态规划也就驾轻就熟了。我一开始来认识动态规划是通过概念来理解的，这对于我来说总是显得晦涩。我不是一个善于死记理论的人，反而是通过多刷题，回头再去看动态规划的使用情况则是有一种恍然大悟感。这样的获得想必也不会轻易忘记。刷题并不能让人变得聪明，但确实能够锻炼一个人的思维。</p>
          </div>
        
        <a class="more" href="/solve-dp-problems.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/lock-of-synchronized.html"><h2>Java 中的偏向锁、轻量级锁和重量级锁</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2019-07-18T16:28:02.000Z">
            2019-07-19
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/JVM/" rel="tag">JVM</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E5%81%8F%E5%90%91%E9%94%81/" rel="tag">偏向锁</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E9%94%81/" rel="tag">锁</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>今天我们来聊聊 Synchronized 里面的各种锁：偏向锁、轻量级锁、重量级锁，以及三个锁之间是如何进行锁膨胀的。</p>
          </div>
        
        <a class="more" href="/lock-of-synchronized.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/2PC-and-3PC.html"><h2>分布式一致性协议学习笔记：2PC 和 3PC</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2019-07-12T15:24:17.000Z">
            2019-07-12
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/BASE/" rel="tag">BASE</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/CAP/" rel="tag">CAP</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E4%B8%80%E8%87%B4%E6%80%A7%E5%8D%8F%E8%AE%AE/" rel="tag">一致性协议</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E5%88%86%E5%B8%83%E5%BC%8F/" rel="tag">分布式</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>了解分布式一致性的一些概念和理论，介绍简单常用的分布式一致性协议。主要介绍二阶段提交和三阶段提交的基本流程，并相互比较。</p>
          </div>
        
        <a class="more" href="/2PC-and-3PC.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/Monty-Hall-problem.html"><h2>三门问题</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2019-06-19T05:13:46.000Z">
            2019-06-19
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E6%A6%82%E7%8E%87%E8%AE%BA/" rel="tag">概率论</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/%E7%AE%97%E6%B3%95/" rel="tag">算法</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>前几天有一个关注很久的公众号推送了一篇讲 “三门问题” 的文章。这不是我第一看到这个问题的分析，我一直觉得这个是个伪命题，后面两个门打开后面有大奖的概率都应该是<code>1/2</code>才对呀。直到我去看了一些分析，写了这篇文章。</p>
          </div>
        
        <a class="more" href="/Monty-Hall-problem.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/ConcurrentModificationException.html"><h2>聊聊 ConcurrentModificationException</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2019-06-03T12:40:32.000Z">
            2019-06-03
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/Java/" rel="tag">Java</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/tech/" rel="tag">tech</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>今天有朋友突然在群里抛出一句，”java中使用foreach遍历时，为啥不让删除元素呢？设计ConcurrentModificationException的意义是什么目的呢？如果单线程操作，还需要吗？” 。今天我们就来聊一聊这件事。</p>
          </div>
        
        <a class="more" href="/ConcurrentModificationException.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/create-right-singleton.html"><h2>如何构建一个正确的单例</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2019-05-30T15:26:28.000Z">
            2019-05-30
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/Java/" rel="tag">Java</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/tech/" rel="tag">tech</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>单例模式是设计模式里面最常见的，也是在面试过程中面试官最容易考到的，通过单例模式还可以引申到其他的一些并发问题。今天我们来聊聊如何正确的构建一个单例。</p>
          </div>
        
        <a class="more" href="/create-right-singleton.html"> 阅读全文〉</a>
      </article>
    

      <article class="recent-post-item">
        <a class="title" href="/record-of-deadlock-analytics.html"><h2>线上死锁分析解决纪实</h2></a>
        <div class="post-meta">
          
          <time class="time" datetime="2019-05-17T08:30:53.000Z">
            2019-05-17
          </time>
          
          <span class="slash">/</span>
          
          <ul class="index-tag-list" itemprop="keywords"><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/MySQL/" rel="tag">MySQL</a></li><li class="index-tag-list-item"><a class="index-tag-list-link" href="/tags/tech/" rel="tag">tech</a></li></ul>
          

        </div>

        
          <div class="post-excerpt">
            <p>服务发生死锁，死锁检测时间较长，31s后死锁检测出来事务才得以回滚，期间不断有相同请求进来，造成死锁越来越复杂，并且服务端线程池中的所有线程都在等待锁，最后造成服务端线程池无空闲线程，拒绝服务。</p>
<p><strong>注意：单条 SQL 也是一个事务，也会和其他事务发生死锁。</strong></p>
          </div>
        
        <a class="more" href="/record-of-deadlock-analytics.html"> 阅读全文〉</a>
      </article>
    
  </div>



    </div>

    
    <nav class="page-nav text-center">
      <span class="page-number current">1</span><a class="page-number" href="/page/2/">2</a><a class="page-number" href="/page/3/">3</a><a class="extend next" rel="next" href="/page/2/">〉</a>
    </nav>
    

  </div>
  <footer class="footer text-center">
    <div id="bottom-inner">
        <a class="bottom-item-hide" href="https://jacobchang.cn/" target="_blank">主站</a>
        <!-- <a class="bottom-item-hide">·</a> -->
        <!-- <a class="bottom-item-hide" href="" target="_blank">备份站点</a> -->
        <a class="bottom-item-hide">·</a>
        <a class="bottom-item-hide" href="https://github.com/coderbean" target="_blank">GitHub</a>
        <a class="bottom-item-hide">·</a>
        <a class="bottom-item" href="https://hexo.io" target="_blank">Powered by hexo</a>
        <a class="bottom-item">·</a>
        <a class="bottom-item" href="https://github.com/coderbean/hexo-theme-xoxo" target="_blank">Theme xoxo</a>
    </div>
    <div id="bottom-inner">
        <a class="bottom-item-hide" target="_blank" rel="noopener" href="https://beian.miit.gov.cn">备案号：浙ICP备2021033778号-1</a> 
        <a class="bottom-item-hide">·</a>
        <a id="copyright" class="bottom-item"></a>
    </div>
</footer>

<script language="javascript" type="text/javascript">
    var df = new Date();
    var year = df.getFullYear();
    document.getElementById("copyright").innerHTML = "Copyright © 2017 – " + year + " 黄小豆";
</script>
  

<script>
  (function(window, document, undefined) {

    var timer = null;

    function returnTop() {
      cancelAnimationFrame(timer);
      timer = requestAnimationFrame(function fn() {
        var oTop = document.body.scrollTop || document.documentElement.scrollTop;
        if (oTop > 0) {
          document.body.scrollTop = document.documentElement.scrollTop = oTop - 50;
          timer = requestAnimationFrame(fn);
        } else {
          cancelAnimationFrame(timer);
        }
      });
    }

    var hearts = [];
    window.requestAnimationFrame = (function() {
      return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(callback) {
          setTimeout(callback, 1000 / 60);
        }
    })();
    init();

    function init() {
      css(".heart{z-index:9999;width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: absolute;}.heart:after{top: -5px;}.heart:before{left: -5px;}");
      attachEvent();
      gameloop();
      addMenuEvent();
    }

    function gameloop() {
      for (var i = 0; i < hearts.length; i++) {
        if (hearts[i].alpha <= 0) {
          document.body.removeChild(hearts[i].el);
          hearts.splice(i, 1);
          continue;
        }
        hearts[i].y--;
        hearts[i].scale += 0.004;
        hearts[i].alpha -= 0.013;
        hearts[i].el.style.cssText = "left:" + hearts[i].x + "px;top:" + hearts[i].y + "px;opacity:" + hearts[i].alpha + ";transform:scale(" + hearts[i].scale + "," + hearts[i].scale + ") rotate(45deg);background:" + hearts[i].color;
      }
      requestAnimationFrame(gameloop);
    }

    /**
     * 设置点击事件
     * 
     * - 回到顶部
     * - 出现爱心
     */
    function attachEvent() {
      var old = typeof window.onclick === "function" && window.onclick;
      var logo = document.getElementById("menu");
      if (logo) {
        logo.onclick = function(event) {
          // returnTop();
          old && old();
          createHeart(event);
        }
      }
      
    }

    function createHeart(event) {
      var d = document.createElement("div");
      d.className = "heart";
      hearts.push({
        el: d,
        x: event.clientX - 5,
        y: event.clientY - 5,
        scale: 1,
        alpha: 1,
        color: randomColor()
      });
      document.body.appendChild(d);
    }

    function css(css) {
      var style = document.createElement("style");
      style.type = "text/css";
      try {
        style.appendChild(document.createTextNode(css));
      } catch (ex) {
        style.styleSheet.cssText = css;
      }
      document.getElementsByTagName('head')[0].appendChild(style);
    }

    function randomColor() {
      // return "rgb(" + (~~(Math.random() * 255)) + "," + (~~(Math.random() * 255)) + "," + (~~(Math.random() * 255)) + ")";
      return "#F44336";
    }

    function addMenuEvent() {
      var menu = document.getElementById('menu-main-post');
      if (menu) {
        var toc = document.getElementById('toc');
        if (toc) {
          menu.onclick = function() {
            if (toc) {
              if (toc.style.display == 'block') {
                toc.style.display = 'none';
              } else {
                toc.style.display = 'block';
              }
            }
          };
        } else {
          menu.style.display = 'none';
        }
      }
    }

  })(window, document);
</script>

  


  <script>
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
                  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
              m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
      ga('create', 'UA-155080039-1', 'auto');
      ga('send', 'pageview');
  </script>


  
<link rel='stylesheet' href='https://s3-us-west-2.amazonaws.com/s.cdpn.io/1462889/unicons.css'>

<div class="progress-wrap">
    <svg class="progress-circle svg-content" width="100%" height="100%" viewBox="-1 -1 102 102">
        <path d="M50,1 a49,49 0 0,1 0,98 a49,49 0 0,1 0,-98" />
    </svg>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js'></script>
<script>

    (function ($) {
        "use strict";
        $(document).ready(function () {
            "use strict";

            //Scroll back to top

            var progressPath = document.querySelector('.progress-wrap path');
            var pathLength = progressPath.getTotalLength();
            progressPath.style.transition = progressPath.style.WebkitTransition = 'none';
            progressPath.style.strokeDasharray = pathLength + ' ' + pathLength;
            progressPath.style.strokeDashoffset = pathLength;
            progressPath.getBoundingClientRect();
            progressPath.style.transition = progressPath.style.WebkitTransition = 'stroke-dashoffset 10ms linear';
            var updateProgress = function () {
                var scroll = $(window).scrollTop();
                var height = $(document).height() - $(window).height();
                var progress = pathLength - (scroll * pathLength / height);
                progressPath.style.strokeDashoffset = progress;
            }
            updateProgress();
            $(window).scroll(updateProgress);
            var offset = 50;
            var duration = 550;
            jQuery(window).on('scroll', function () {
                if (jQuery(this).scrollTop() > offset) {
                    jQuery('.progress-wrap').addClass('active-progress');
                } else {
                    jQuery('.progress-wrap').removeClass('active-progress');
                }
            });
            jQuery('.progress-wrap').on('click', function (event) {
                event.preventDefault();
                jQuery('html, body').animate({ scrollTop: 0 }, duration);
                return false;
            })


        });

    })(jQuery);
</script>

  
<!-- for theme: default is false -->
<!-- for page: default is true -->
<!-- 图片查看器实例配置 -->
<script type="text/javascript">
    //默认设置， 可以根据个人需求和喜好进行配置
    //详细参考官方说明
    Viewer.setDefaults({
        //设置初始缩放 default: 1
        zoomRatio: [0.5],
        // 过渡动画
        transition:true,
        // 显示工具条
        toolbar: false,
    });
    //获得content中所有的图片， 不同主题可能有所不同
    //为了和其他的图片区别开来 所以在markdown中插入图片的时候使用独特的记号
    //为了一次性得到所有的图片我这里采用的是class = 'article-image'
    var article = document.querySelector('.post-content');
    if(article!=null) {
        var imageList = article.getElementsByTagName('img');
        //将获取到的HTMLCollections转化成Array
        var imageArray = new Array();
        Array.prototype.forEach.call(imageList, element => {
            imageArray.push(element);
        });
        //设置每个图片成为图片组
        Array.prototype.forEach.call(imageList, element => {
            var viewer1 = new Viewer(element);
            viewer1.images = imageArray;
            viewer1.length = imageArray.length;
        });
    }

    
</script>

  
  <! -- mathjax config similar to math.stackexchange -->

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
                processEscapes: true
                    
}
  
        });
</script>

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
            skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
                  
}
    
        });
</script>

<script type="text/x-mathjax-config">
MathJax.Hub.Queue(function() {
            var all = MathJax.Hub.getAllJax(), i;
            for(i=0; i < all.length; i += 1) {
                            all[i].SourceElement().parentNode.className += ' has-jax';
                                    
            }
                
        });
</script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"></script>

</script>

  
</body>

</html>